#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
#
# SPDX-License-Identifier: BSD-2-Clause
#
#

from __future__ import absolute_import, division, print_function, \
    unicode_literals
from camkes.internal.tests.utils import CAmkESTest, c_compiler
from camkes.ast.ckeywords import C_KEYWORDS

import os
import subprocess
import sys
import tempfile
import unittest

ME = os.path.abspath(__file__)

# Make CAmkES importable
sys.path.append(os.path.join(os.path.dirname(ME), '../../..'))


class TestCKeywords(CAmkESTest):
    '''
    Test generation of the file ckeywords.py.
    '''

    @unittest.skipIf(c_compiler() is None, 'C compiler not available')
    def test_missing(self):
        '''
        Check if there are C keywords our local Clang is aware of that are not
        noted in ckeywords.py.
        '''

        cc = c_compiler()
        assert cc is not None

        # Check we can #include TokenKinds.def, otherwise there's no point
        # continuing.
        with open(os.devnull, 'wt') as f:
            p = subprocess.Popen([cc, '-x', 'c', '-E', '-'], stdout=f, stderr=f,
                                 stdin=subprocess.PIPE, universal_newlines=True)
            p.communicate('#include <TokenKinds.def>\n')
            if p.returncode != 0:
                self.skipTest('TokenKinds.def unavailble for including (try '
                              'setting C_INCLUDE_PATH)')

        tmp = self.mkdtemp()

        src = os.path.join(os.path.dirname(ME), '../../../tools/ckeywords.c')
        assert os.path.exists(src)

        # Compile the C keyword generator.
        aout = os.path.join(tmp, 'a.out')
        subprocess.check_call([cc, src, '-std=c11', '-W', '-Wall', '-Wextra',
                               '-Werror', '-o', aout])

        generated = subprocess.check_output([aout])

        # Unsafe, but we trust the generated code.
        namespace = {}
        exec(generated in namespace)

        self.assertIn('C_KEYWORDS', namespace, 'C keywords apparently not '
                      'generated by keyword generator')
        new_keywords = namespace['C_KEYWORDS']

        # Check for keywords picked up locally that are not recognised by the
        # AST sources. We don't bother checking the other way around because the
        # AST sources may recognise extended keywords that our current compiler
        # does not.
        diff = new_keywords - C_KEYWORDS
        self.assertEqual(diff, set([]), 'extra C keywords (%s) found that are '
                         'not currently recognised' % ', '.join(diff))


if __name__ == '__main__':
    unittest.main()
